package com.gao.f_reactor.c.server;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author gao
 * @time 2020/08/16 13:17:45
 */
public class Handler implements Runnable {
    public static final int READING = 0, WRITTING = 1;
    private int state;
    private final SocketChannel channel;
    private final Selector selector;
    private SelectionKey key;

    // 该线程池是被static修饰的，也就是全局的
    private static ExecutorService es = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

    public Handler(SocketChannel channel, Selector selector) throws IOException {
        this.channel = channel;
        this.selector = selector;
        channel.configureBlocking(false);
        key = this.channel.register(selector, SelectionKey.OP_READ);
        key.attach(this);
        state = READING;
    }

    @Override
    public void run() {
        if (state == READING) {
            read();
        } else if (state == WRITTING) {
            write();
        }
    }

    private String msg = "";

    private  void read() {
        // 为了解决重复消费key的问题，需要把以下代码从“处理完read”之后的位置，提前到“处理read”之前的位置
        key.interestOps(SelectionKey.OP_WRITE);
        state = WRITTING;

        es.submit(() -> {
            // 让读和写操作竞争同一把锁，防止读操作还没有完成，写操作就执行，反之亦然。
            synchronized (Handler.this) {
                try {
                    ByteBuffer buffer = ByteBuffer.allocate(100);
                    int n = channel.read(buffer);
                    if (n == 0) return;
                    buffer.flip();
                    byte[] readBytes = new byte[n];
                    buffer.get(readBytes);
                    msg = new String(readBytes);
                    System.out.println("recv msg: " + msg);

                    if ("bye".equalsIgnoreCase(msg)) {
                        key.cancel();
                        channel.close();
                        System.out.println("client退出");
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });


    }

    private  void write() {
        // 为了解决重复消费key的问题，需要把以下代码从“处理完write”之后的位置，提前到“处理write”之前的位置
        key.interestOps(SelectionKey.OP_READ);
        state = READING;

        es.submit(() -> {
            synchronized (Handler.this) {
                if ("".equalsIgnoreCase(msg)) {
                    return;
                }
                try {
                    if (msg.equalsIgnoreCase("what's the time")) {
                        Date now = new Date();
                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                        String str = sdf.format(now);
                        channel.write(ByteBuffer.wrap(str.getBytes()));
                        msg = "";
                    } else {
                        channel.write(ByteBuffer.wrap("it dose not make sense...".getBytes()));
                        msg = "";
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}
